package com.cherish.web.user.controller;

import com.cherish.config.jwt.JwtUtils;
import com.cherish.config.security.exception.TokenException;
import com.cherish.redis.RedisService;
import com.cherish.utils.ResultUtils;
import com.cherish.utils.ResultVo;
import com.cherish.web.menu.entity.MakeMenuTree;
import com.cherish.web.menu.entity.Menu;
import com.cherish.web.user.entity.RouterVO;
import com.cherish.web.user.entity.TokenVo;
import com.cherish.web.user.entity.User;
import com.cherish.web.user.entity.UserInfo;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import io.jsonwebtoken.Jwts;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Author:MQ
 * Date:2024/1/221:51
 */
@Api(tags = "用户登录、权限查询")
@RestController
@RequestMapping("/api/sysUser")
public class SysUserController {
    @Autowired
    private DefaultKaptcha defaultKaptcha;
    @Autowired
    private RedisService redisService;
    @Autowired
    private JwtUtils jwtUtils;


    @ApiOperation(value="登录用户信息SysUser")
    @GetMapping("/getCurrentUser")
    public ResultVo getCurrentUser(){
        //从spring security上下文获取用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication == null){
            return ResultUtils.error("查询失败!");
        }
        User user =  (User)authentication.getPrincipal();
        UserInfo userInfo = new UserInfo();
        userInfo.setName(user.getUsername());
        userInfo.setId(user.getFId());
        List<Menu> permissionList = user.getPermissionList();
        //3.获取code字段，返回给前端role使用
        Object[] roles = permissionList.stream().filter(item -> item != null)
                .map(item -> item.getFCode()).toArray();
        userInfo.setRoles(roles);
        return ResultUtils.success("查询成功!",userInfo);
    }

    @ApiOperation(value="获取菜单数据")
    @GetMapping("/getMenuList")
    public ResultVo getMenuList(){
        //获取用户相关的信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //获取用户信息
        User user = (User) authentication.getPrincipal();
        //获取权限
        List<Menu> permissionList = user.getPermissionList();
        //只需要获取目录和菜单
        List<Menu> collect = permissionList.stream().filter(item -> item != null
                && !item.getFType().equals("2")).collect(Collectors.toList());
        List<RouterVO> routerVOList = MakeMenuTree.makeRouter(collect, 0L);
        return ResultUtils.success("获取成功",routerVOList);
    }

    @ApiOperation(value = "登录验证码")
    @PostMapping("/image")
    public void imageCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //设置页面缓存方式   不缓存，不存储
        response.setHeader("Cache-Control","no-store, no-cache");
        //设置以图片的形式响应
        response.setContentType("image/jpeg");
        //1.获取验证码字符
        String yzm = defaultKaptcha.createText();
        //2.获取ip
        String ip =request.getRemoteAddr();
        //3.存储到redis中
        //redis的key
        String key = ip+yzm;
        //设置验证码15S过期
        redisService.set(key,yzm,15L);
        //3.生成验证码图片
        BufferedImage image = defaultKaptcha.createImage(yzm);
        //4.输出给前端
        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image,"jpg",out);
        if(out != null){
            out.close();
        }
    }

    @ApiOperation(value = "退出登录")
    @PostMapping("/loginOut")
    public ResultVo loginOut(HttpServletRequest request, HttpServletResponse response){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication != null){
            new SecurityContextLogoutHandler().logout(request,response,authentication);
        }
        return ResultUtils.success("退出成功!");
    }

    @ApiOperation(value="刷新token", notes="刷新token")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "token",value = "token")
    })
    @PostMapping(value = "/refreshToken")
    public ResultVo refreshToken(HttpServletRequest request){
        //获取前端传来的token  首先从header里面取，如果没有，从参数里面取
        String token = request.getHeader("token");
        if(StringUtils.isEmpty(token)){
            token = request.getParameter("token");
        }
        if(StringUtils.isBlank(token)){
            throw new TokenException("token不能为空!");
        }
        String reToken = "";
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserDetails details = (UserDetails) authentication.getPrincipal();
        //验证原来的token是否合法
        Boolean aBoolean = jwtUtils.validateToken(token, details);
        if(aBoolean){
            //生成新的token
            reToken = jwtUtils.refreshToken(token);
        }
        //取出本次token到期的时间,返回前端做判断
        long expireTime = Jwts.parser()   //得到DefaultJwtParser
                .setSigningKey(jwtUtils.getSecret())  //设置签名的秘钥
                .parseClaimsJws(reToken.replace("jwt_", ""))
                .getBody().getExpiration().getTime();
        //清除原来的token
        String oldTokenKey = "token_"+token;
        redisService.del(oldTokenKey);
        //存储新的token
        String newTokenKey = "token_"+reToken;
        redisService.set(newTokenKey,reToken,jwtUtils.getExpiration()/1000);
        TokenVo vo = new TokenVo();
        vo.setFToken(reToken);
        vo.setFExpireTime(expireTime);
        return ResultUtils.success("生成token成功!",vo);
    }
}
